#include <GameEngine/UnitTest/unit_test.h>

#include <GameEngine/Core/Graph/quadtree.h>


#ifdef GAMEENGINE_NAMESPACES
namespace GameEngine {
#endif


//! Launch the unit tests on Quadtree objects
/*!
 @return True if all unit tests on Quadtree objects were
         succesful, false otherwise
 */
bool UnitTest::test_core_quadtree_functions() {
	bool res = true;

	// Get number of bytes
	MemoryManager::BytesCount bytes = MemoryManager::instance()->bytes();

	// Create quadtree
	GameEngine::Quadtree<int,float> tree(2);

	// Test iterator
	{{
		int nb_nodes = 0;
		for ( GameEngine::Quadtree<int,float>::Node::IteratorConst it(tree.node(), GameEngine::QuadtreeNodeItr::NonEmptyNodes); it.more(); it.next() ) {
			++nb_nodes;
		}
		res &= UNIT_TEST_ERROR( "[Quadtree] Test IteratorConst()", ( nb_nodes == 0 ) );
	}}

	// Test add elements
	{{
		bool b = tree.add_element( 0, GameEngine::Point2d<float>(0.4f, 0.1f) ); // index = 0
		b &= tree.add_element( 1, GameEngine::Point2d<float>(0.3f, 0.15f) );    // index = 1
		b &= tree.add_element( 2, GameEngine::Point2d<float>(0.4f, 0.45f) );    // index = 2
		b &= tree.add_element( 3, GameEngine::Point2d<float>(0.45f, 0.65f) );   // index = 3
		b &= tree.add_element( 4, GameEngine::Point2d<float>(0.8f, 0.9f) );     // index = 4
		res &= UNIT_TEST_ERROR( "[Quadtree] Test add_element()", b );
	}}

	// Test get node
	{{
		const GameEngine::Quadtree<int,float>::Node* node = tree.get_node( GameEngine::Point2d<float>(0.45f, 0.65f) );
		res &= UNIT_TEST_ERROR( "[Quadtree] Test get_node()", ( node != nil ) );
		if ( node != nil ) {
			res &= UNIT_TEST_ERROR( "[Quadtree] Test get_node()", ( *node->elements().begin() == 3 ) );
		}
	}}

	// Test get node
	{{
		const GameEngine::Quadtree<int,float>::Node* node = tree.get_node( GameEngine::Point2d<float>(0.375, 0.125) );
		res &= UNIT_TEST_ERROR( "[Quadtree] Test get_node()", ( node != nil ) );
		if ( node != nil ) {
			res &= UNIT_TEST_ERROR( "[Quadtree] Test get_node()", ( node->elements().size() == 2 ) );
			if ( node->elements().size() >= 3 ) {
				std::vector<GameEngine::Quadtree<int,float>::QuadtreeIndex>::const_iterator it = node->elements().begin();
				res &= UNIT_TEST_ERROR( "[Quadtree] Test get_node()", ( *it == 0 ) ); ++it;
				res &= UNIT_TEST_ERROR( "[Quadtree] Test get_node()", ( *it == 1 ) );
			}
		}
	}}

	// Test get nodes
	{{
		std::list< GameEngine::Quadtree<int,float>::Node* > list = tree.get_nodes( GameEngine::Box2d<float>(0.45f, 0.65f, 0.35f, 0.45f),
			GameEngine::QuadtreeNodeItr::NonEmptyNodes );
		res &= UNIT_TEST_ERROR( "[Quadtree] Test get_nodes()", ( list.size() == 1 ) );
		if ( list.size() >= 1 ) {
			GameEngine::Quadtree<int,float>::Node* first_node = *list.begin();
			res &= UNIT_TEST_ERROR( "[Quadtree] Test get_nodes()", ( *first_node->elements().begin() == 2 ) );
		}
	}}

	// Test iterator
	{{
		int nb_nodes = 0;
		for ( GameEngine::Quadtree<int,float>::Node::IteratorConst it(tree.node(), GameEngine::QuadtreeNodeItr::LowLevelNodes); it.more(); it.next() ) {
			++nb_nodes;
		}
		res &= UNIT_TEST_ERROR( "[Quadtree] Test IteratorConst()", ( nb_nodes == 16 ) );
	}}

	// Test iterator
	{{
		int nb_nodes = 0;
		for ( GameEngine::Quadtree<int,float>::Node::IteratorConst it(tree.node(), GameEngine::QuadtreeNodeItr::AllNodes); it.more(); it.next() ) {
			++nb_nodes;
		}
		res &= UNIT_TEST_ERROR( "[Quadtree] Test IteratorConst()", ( nb_nodes == 21 ) );
	}}

	// Test iterator
	{{
		int nb_nodes = 0;
		for ( GameEngine::Quadtree<int,float>::Node::IteratorConst it(tree.node(), GameEngine::QuadtreeNodeItr::NonEmptyNodes); it.more(); it.next() ) {
			++nb_nodes;
		}
		res &= UNIT_TEST_ERROR( "[Quadtree] Test IteratorConst()", ( nb_nodes == 4 ) );
	}}

	// Test simplify
	{{
		res &= UNIT_TEST_ERROR( "[Quadtree] Test simplify()", tree.simplify(1) );
	}}

	// Test iterator
	{{
		int nb_nodes = 0;
		for ( GameEngine::Quadtree<int,float>::Node::IteratorConst it(tree.node(), GameEngine::QuadtreeNodeItr::AllNodes); it.more(); it.next() ) {
			++nb_nodes;
		}
		res &= UNIT_TEST_ERROR( "[Quadtree] Test IteratorConst()", ( nb_nodes == 17 ) );
	}}

	// Test iterator
	{{
		int nb_nodes = 0;
		for ( GameEngine::Quadtree<int,float>::Node::IteratorConst it(tree.node(), GameEngine::QuadtreeNodeItr::NonEmptyNodes); it.more(); it.next() ) {
			++nb_nodes;
		}
		res &= UNIT_TEST_ERROR( "[Quadtree] Test IteratorConst()", ( nb_nodes == 4 ) );
	}}

	// Test iterator
	{{
		int nb_nodes = 0;
		for ( GameEngine::Quadtree<int,float>::Node::IteratorConst it(tree.node(), GameEngine::QuadtreeNodeItr::LowLevelNodes); it.more(); it.next() ) {
			++nb_nodes;
		}
		res &= UNIT_TEST_ERROR( "[Quadtree] Test IteratorConst()", ( nb_nodes == 13 ) );
	}}

	// Test find/remove element
	{{
		res &= UNIT_TEST_ERROR( "[Quadtree] Test find_element()", ( tree.find_element(4) == true ) );
		res &= UNIT_TEST_ERROR( "[Quadtree] Test find_element()", ( tree.find_element(7) == false ) );
		res &= UNIT_TEST_ERROR( "[Quadtree] Test remove_element()", ( tree.remove_element(4) == 1 ) );
		res &= UNIT_TEST_ERROR( "[Quadtree] Test find_element()", ( tree.find_element(4) == false ) );
	}}

	// Test simplify/iterator
	{{
		res &= UNIT_TEST_ERROR( "[Quadtree] Test simplify()", tree.simplify(1) );
		int nb_nodes = 0;
		for ( GameEngine::Quadtree<int,float>::Node::IteratorConst it(tree.node(), GameEngine::QuadtreeNodeItr::LowLevelNodes); it.more(); it.next() ) {
			++nb_nodes;
		}
		res &= UNIT_TEST_ERROR( "[Quadtree] Test IteratorConst()", ( nb_nodes == 10 ) );
	}}

	// Test simplify/iterator
	{{
		res &= UNIT_TEST_ERROR( "[Quadtree] Test simplify()", tree.simplify() );
		int nb_nodes = 0;
		for ( GameEngine::Quadtree<int,float>::Node::IteratorConst it(tree.node(), GameEngine::QuadtreeNodeItr::LowLevelNodes); it.more(); it.next() ) {
			++nb_nodes;
		}
		res &= UNIT_TEST_ERROR( "[Quadtree] Test IteratorConst()", ( nb_nodes == 1 ) );
	}}

	// Get number of bytes
	res &= UNIT_TEST_ERROR( "[Quadtree] Test memory leak", ( bytes == MemoryManager::instance()->bytes() ));

	// Return result
	return res;
}


#ifdef GAMEENGINE_NAMESPACES
} // namespace GameEngine
#endif
